import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import type { InternalAxiosRequestConfig } from 'axios'
import { ContentType } from '@/enum'
import { getToken } from '@/utils/index'
import { errorHandler } from '@/service/request/errorHandler'
import qs from 'qs'
import { REQUEST_TIMEOUT } from './config'

export interface StatusConfig {
  /**
   * 表明请求状态的属性 key
   */
  statusKey: string
  /**
   * 请求信息的属性 key
   */
  msgKey: string
  /**
   * 有效载荷的属性 key
   */
  dataKey: string
  /**
   * 成功状态的属性 key
   */
  successKey: string
  /**
   * 成功状态的状态码
   */
  successStatusCode: string | number
}

export default class CustomAxiosInstance {
  instance: AxiosInstance

  // CreateAxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'>
  // 因为 AxiosRequestConfig 的属性是 CreateAxiosDefaults 的超集，因此不报错
  constructor(
    axiosConfig: AxiosRequestConfig = {},
    statusConfig: StatusConfig = {
      statusKey: 'code',
      msgKey: 'message',
      dataKey: 'result',
      successKey: 'success',
      successStatusCode: 200,
    }
  ) {
    // this.instance = axios.create(axiosConfig)
    this.instance = axios.create({
      timeout: REQUEST_TIMEOUT,
      // 默认 withCredentials 为 true，会导致 cors
      withCredentials: false,
      ...axiosConfig,
    })
    this.setInterceptor(statusConfig)
  }

  /** 设置请求拦截器 */
  setInterceptor(statusConfig: StatusConfig) {
    this.instance.interceptors.request.use(
      async (config: InternalAxiosRequestConfig) => {
        // 将 config 复制为 handleConfig
        const handleConfig = { ...config }
        // content-type 为 application/x-www-form-urlencoded 类型的 data 参数需要序列化
        // enum ContentType 为 string 类型
        if (handleConfig.headers['Content-Type'] === ContentType.formUrlEncoded) {
          handleConfig.data = qs.stringify(handleConfig.data)
        }
        // 设置 token
        handleConfig.headers.Authorization = getToken()

        return handleConfig
      },
      (error) => {
        errorHandler(error)
        return Promise.reject(error)
      }
    )

    this.instance.interceptors.response.use(
      (response) => {
        console.log('###', response)
        const { status, data } = response
        const { statusKey, msgKey, dataKey, successKey, successStatusCode } = statusConfig
        if (status === 200 || status < 300 || status === 304) {
          // 在业务中也有一个表示状态的字段
          if (data[successKey] && data[statusKey] === successStatusCode) {
            // 如果业务正确
            return Promise.resolve(data[dataKey])
          }
          window.$message?.error(data[msgKey])
          return Promise.reject({ [msgKey]: data[msgKey], [statusKey]: data[statusKey] })
        }
        const error = { response }
        errorHandler(error)
        return Promise.reject(error)
      },
      (error) => {
        errorHandler(error)
        return Promise.reject(error)
      }
    )
  }
}
